import {Vector3} from "../math/Vector3";
import {Vector2} from "../math/Vector2";
import {Box3} from "../math/Box3";
import {Texture} from "./Texture";

interface Face {
    vertexIndexes: number[];
    uvIndexes: number[];
    normalIndexes: number[];
}

function genFace(str: string): Face {
    const face: Face = {
        vertexIndexes: [],
        uvIndexes: [],
        normalIndexes: [],
    }
    for (const pointInfo of str.split(' ')) {
        const indexInfo = pointInfo.split('/').map(Number);
        face.vertexIndexes.push(indexInfo[0] - 1);
        face.uvIndexes.push(indexInfo[1] - 1);
        face.normalIndexes.push(indexInfo[2] - 1);
    }
    return face;
}
interface VertexInfo {
    vertex: Vector3;
    uv: Vector2;
    normal: Vector3;
}
interface WrapFace {
    vertexInfos: VertexInfo[];
}

export class ObjFile {
    vertexes: Vector3[] = [];
    uvs: Vector2[] = [];
    normals: Vector3[] = [];
    faces: Face[] = [];
    wrapFaces: WrapFace[] = [];
    box: Box3;

    loadString(data: string) {
        this.vertexes = [];
        this.uvs = [];
        this.normals = [];
        this.faces = [];
        this.wrapFaces = [];
        for (const line of data.split('\r\n')) {
            if (line.startsWith('v ')) {
                this.vertexes.push(new Vector3().loadFromString(line.substr(2)));
            } else if (line.startsWith('vt ')) {
                this.uvs.push(new Vector2().loadFromString(line.substr(3)));
            } else if (line.startsWith('vn ')) {
                this.normals.push(new Vector3().loadFromString(line.substr(3)));
            } else if (line.startsWith('f ')) {
                this.faces.push(genFace(line.substr(2)));
            }
        }
        for (const face of this.faces) {
            const wrapFace: WrapFace = {
                vertexInfos: []
            };
            for (let i = 0; i<3; i++) {
                wrapFace.vertexInfos.push({
                    vertex: this.vertexes[face.vertexIndexes[i]],
                    uv: this.uvs[face.uvIndexes[i]],
                    normal: this.normals[face.normalIndexes[i]]
                });
            }
            this.wrapFaces.push(wrapFace);
        }
        this.box = new Box3(this.vertexes);
        return this;
    }
    static async loadUrl(url: string): Promise<ObjFile> {
        const re = await fetch(url)
        const text = await re.text();
        return new ObjFile().loadString(text);
    }
}